package com.enba.mallapi.aop;

import com.enba.boot.core.context.SecurityContextHolder;
import com.enba.boot.core.exception.BizException;
import com.enba.boot.redis.RedisOperator;
import com.enba.mallapi.annotation.DistributedLock;
import java.lang.reflect.Method;
import java.util.concurrent.TimeUnit;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Aspect
@Component
public class DistributedLockAspect {

  @Autowired private RedisOperator redisOperator;

  @Around("@annotation(com.enba.mallapi.annotation.DistributedLock)")
  public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
    MethodSignature signature = (MethodSignature) joinPoint.getSignature();
    Method method = signature.getMethod();
    DistributedLock lockAnnotation = method.getAnnotation(DistributedLock.class);

    // 锁key
    String key =
        "submit:prevent:"
            + SecurityContextHolder.getUserId()
            + ":"
            + method.getName()
            + ":"
            + lockAnnotation.key();
    // 过期时间
    long expireTime = lockAnnotation.expireTime();
    // 异常提示信息
    String tips = lockAnnotation.tips();

    // 获取锁
    boolean isLocked = redisOperator.setIfAbsent(key, "locked", expireTime, TimeUnit.SECONDS);
    if (!isLocked) {
      BizException.throwEx(tips);
    }

    try {
      // 执行方法
      return joinPoint.proceed();
    } finally {
      // 释放锁
      redisOperator.delete(key);
    }
  }
}
